import 'package:flutter/services.dart';

import 'data_repository_interface.dart';

class DataRepositoryManager {
  static final DataRepositoryManager instance =
      DataRepositoryManager._internal();

  final MethodChannel _channel = const MethodChannel('data-repositories');
  final Map<String, DataRepositoryFactory> _factories = {};

  DataRepositoryManager._internal() {
    _channel.setMethodCallHandler((call) async {
      if (call.arguments is! Map) {
        return false;
      }

      Map arguments = call.arguments as Map;
      if (!arguments.containsKey('id') || arguments['id'] is! String) {
        return false;
      }

      DataRepositoryFactory? factory = _factories[arguments['id'] as String];
      if (factory == null) {
        return false;
      }

      DataRepositoryInterface dataRepository = factory();

      switch (call.method) {
        case 'onDataChanged':
          if (!arguments.containsKey('data')) {
            dataRepository.onDataChanged(null);
          } else {
            dataRepository.onDataChanged(arguments['data']);
          }

          return true;

        case 'onItemChanged':
          if (!arguments.containsKey('item')) {
            return false;
          }

          dataRepository.onItemChanged(arguments['item']);
          return true;

        default:
          return false;
      }
    });
  }

  void register(String id, DataRepositoryFactory factory) {
    _factories[id] = factory;
  }

  DataRepositoryInterface? getDataRepository(String id) {
    DataRepositoryFactory? factory = _factories[id];
    return factory?.call();
  }

  Future<bool?> setData(String id, dynamic data) async {
    return _channel.invokeMethod<bool>('setData', {'id': id, 'data': data});
  }

  Future<bool?> updateItem(String id, dynamic item) async {
    return _channel.invokeMethod<bool>('updateItem', {'id': id, 'item': item});
  }

  Future<bool?> updateItemValue(
    String id, {
    required String itemId,
    required String key,
    dynamic value,
  }) async {
    return _channel.invokeMethod<bool>('updateItemValue', {
      'id': id,
      'itemId': itemId,
      'key': key,
      'value': value,
    });
  }

  Future<bool?> addItem(String id, dynamic data) async {
    return _channel.invokeMethod<bool>('addItem', {'id': id, 'data': data});
  }

  Future<bool?> insertItem(String id, dynamic data) async {
    return _channel.invokeMethod<bool>('insertItem', {'id': id, 'data': data});
  }

  Future<dynamic> getData(String id) async {
    return _channel.invokeMethod<dynamic>('getData', {'id': id});
  }

  Future<dynamic> getItem(String id, int index) async {
    return _channel.invokeMethod('getItem', {'id': id, 'item': index});
  }

  Future<dynamic> getItemById(String id, String itemId) async {
    return _channel.invokeMethod(
      'getItemById',
      {
        'id': id,
        "itemId": itemId,
      },
    );
  }

  Future<bool?> removeItemById(String id, String itemId) async {
    return _channel.invokeMethod<bool>(
      'removeItemById',
      {
        'id': id,
        "itemId": itemId,
      },
    );
  }
}
